home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / kernel / mkrivers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-06  |  6.7 KB  |  257 lines  |  [TEXT/KAHL]

  1. /* River generation for Xconq.
  2.    Copyright 1991, 1992, 1993, 1994 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. /* This river generator requires elevations. */
  10.  
  11. #include "conq.h"
  12.  
  13. extern int make_rivers PROTO ((void));
  14. static void make_up_river_borders PROTO ((int rivertype));
  15. static int border_is_compatible PROTO ((int x, int y, int dir, int b));
  16. static int elev_in_dir PROTO ((int x, int y, int dir));
  17. static int elev_at_meet PROTO ((int x, int y, int dir));
  18. static void set_river_at PROTO ((int x, int y, int dir, int t));
  19. static void make_up_river_connections PROTO ((int rivertype));
  20.  
  21. static long totalrivers;
  22.  
  23. /* Add rivers by picking a headwater randomly, then running downhill. */
  24.  
  25. /* Can do as either a border or connection type, depending on which
  26.    terrain type is called "river". */
  27.  
  28. int
  29. make_rivers()
  30. {
  31.     int x, y, t;
  32.  
  33.     totalrivers = 0;
  34.     for_all_cells(x, y) {
  35.     totalrivers += t_river_chance(terrain_at(x, y));
  36.     }
  37.     if (totalrivers <= 0) return FALSE;
  38.     totalrivers /= 10000;
  39.     totalrivers = max(1, totalrivers);
  40.     if (elevations_defined()) {
  41.     for_all_terrain_types(t) {
  42.         if (t_subtype_x(t) == keyword_value(K_RIVER_X)
  43.         && !aux_terrain_defined(t)) {
  44.         if (t_is_border(t)) {
  45.             make_up_river_borders(t);
  46.         } else if (t_is_connection(t)) {
  47.             make_up_river_connections(t);
  48.         }
  49.         }
  50.     }
  51.     }
  52.     return TRUE;
  53. }
  54.  
  55. static int touchedwater;
  56.  
  57. static void
  58. make_up_river_borders(rivertype)
  59. int rivertype;
  60. {
  61.     int j, x, y, dir, elev, x1, y1, d1, e1, x2, y2, d2, e2;
  62.     int x0, y0, numrivers = 0, numrivs;
  63.     int low, lowdir;
  64.     int t, watery[MAXTTYPES];
  65.  
  66.     announce_lengthy_process("Creating rivers (as borders)");
  67.     allocate_area_aux_terrain(rivertype);
  68.     for_all_interior_cells(x0, y0) {
  69.         if (y0 % 2 != 0 || x0 % 2 != 0) continue;
  70.     if (probability(t_river_chance(terrain_at(x0, y0)) / 100)) {
  71.         ++numrivers;
  72.         touchedwater = FALSE;
  73.         if (numrivers % 5 == 0)
  74.           announce_progress((100 * numrivers) / totalrivers);
  75.         x = x0;  y = y0;
  76.         /* Set the initial river direction. */
  77.         lowdir = 0;
  78.         low = elev_at_meet(x, y, lowdir);
  79.         for_all_directions(dir) {
  80.         if (elev_at_meet(x, y, dir) < low) {
  81.             lowdir = dir;
  82.             low = elev_at_meet(x, y, lowdir); 
  83.         }
  84.         }
  85.         dir = lowdir;
  86.         /* We do a right-hand -> downhill rule, so may need to flip around
  87.            and look at/work with river on opposite side. */
  88.         point_in_dir(x, y, dir, &x1, &y1);
  89.         if (elev_at_meet(x, y, dir) <
  90.             elev_at_meet(x1, y1, opposite_dir(dir))) {
  91.         x = x1;  y = y1;
  92.         dir = opposite_dir(dir);
  93.         }
  94.         if (border_is_compatible(x, y, dir, rivertype)) {
  95.         set_river_at(x, y, dir, rivertype);
  96.         } else {
  97.         continue;
  98.         }
  99.         for (j = 0; j < 20; ++j) {  /* why 20?? */
  100.         if (!inside_area(x, y)) break;
  101.         elev = elev_at_meet(x, y, dir);
  102.         /* Compute cell and dir of the two possible ways to flow. */
  103.         point_in_dir(x, y, right_dir(dir), &x1, &y1);
  104.         d1 = left_dir(dir);
  105.         e1 = elev_at_meet(x1, y1, d1);
  106.         x2 = x;  y2 = y;
  107.         d2 = right_dir(dir);
  108.         e2 = elev_at_meet(x2, y2, d2);
  109.         if (elev < e1 && elev < e2) {
  110.             init_warning("river going uphill??");
  111.             break;
  112.         }
  113.         /* Pick the lower of the two. */
  114.         if (e1 < e2) {
  115.             x = x1;  y = y1;  dir = d1;
  116.         } else {
  117.             x = x2;  y = y2;  dir = d2;
  118.         }
  119.         /* Rivers always follow the same paths, so if we see a river
  120.            here already, we're done. */
  121.         if (border_at(x, y, dir, rivertype))
  122.           break;
  123.         if (border_is_compatible(x, y, dir, rivertype))
  124.           set_river_at(x, y, dir, rivertype);
  125.         }
  126.     }
  127.     }
  128.     /* Cells surrounded by river should maybe be set specially. */
  129.     if (g_river_sink_terrain() != NONTTYPE) {
  130.     for_all_cells(x, y) {
  131.         if (inside_area(x, y)) {
  132.         numrivs = 0;
  133.         for_all_directions(dir) {
  134.             if (border_at(x, y, dir, rivertype)) ++numrivs;
  135.         }
  136.         if (numrivs >= NUMDIRS) {
  137.             set_terrain_at(x, y, g_river_sink_terrain());
  138.         }
  139.         }
  140.     }
  141.     }
  142.     /* Fix any bad adjacencies that got through. */
  143.     for_all_terrain_types(t) {
  144.         watery[t] = t_liquid(t);
  145.     }
  146.     for_all_interior_cells(x, y) {
  147.         if (watery[(int) terrain_at(x, y)]) {
  148.         for_all_directions(dir) {
  149.             set_border_at(x, y, dir, rivertype, FALSE);
  150.         }
  151.         }
  152.     }
  153.     finish_lengthy_process();
  154. }
  155.  
  156. static int
  157. border_is_compatible(x, y, dir, b)
  158. int x, y, dir, b;
  159. {
  160.     int x1, y1;
  161.  
  162.     return (tt_adj_terr_effect(terrain_at(x, y), b) < 0
  163.             && point_in_dir(x, y, dir, &x1, &y1)
  164.         && tt_adj_terr_effect(terrain_at(x1, y1), b) < 0);
  165. }
  166.  
  167. static int
  168. elev_in_dir(x, y, dir)
  169. int x, y, dir;
  170. {
  171.     int x1, y1;
  172.  
  173.     if (point_in_dir(x, y, dir, &x1, &y1)) {
  174.     return elev_at(x1, y1);
  175.     } else {
  176.     /* It's possible that the algorithm will ask for the elevation
  177.        of a point not in the area, but it's an obscure case, and
  178.        doesn't hurt to return an arbitrary elevation. */
  179.     return 0;
  180.     }
  181. }
  182.  
  183. /* The elevation at the junction of three cells is the lowest of the three. */
  184.  
  185. static int
  186. elev_at_meet(x, y, dir)
  187. int x, y, dir;
  188. {
  189.     int elev = elev_at(x, y);
  190.  
  191.     if (elev_in_dir(x, y, dir) < elev)
  192.       elev = elev_in_dir(x, y, dir);
  193.     if (elev_in_dir(x, y, right_dir(dir)) < elev)
  194.       elev = elev_in_dir(x, y, right_dir(dir));
  195.     return elev;
  196. }
  197.  
  198. /* should have various conditions */
  199.  
  200. static void
  201. set_river_at(x, y, dir, t)
  202. int x, y, dir, t;
  203. {
  204.     int x1, y1;
  205.  
  206.     if (touchedwater) {
  207.     } else if (t_liquid(terrain_at(x, y))) {
  208.     touchedwater = TRUE;
  209.     } else if (point_in_dir(x, y, dir, &x1, &y1)
  210.            && t_liquid(terrain_at(x1, y1))) {
  211.     touchedwater = TRUE;
  212.     } else {
  213.     set_border_at(x, y, dir, t, TRUE);
  214.     }
  215. }
  216.  
  217. static void
  218. make_up_river_connections(rivertype)
  219. int rivertype;
  220. {
  221.     int x0, y0, i, x, y, x1, y1, dir;
  222.     int numrivers = 0, lowdir, lowx, lowy, low;
  223.     
  224.     allocate_area_aux_terrain(rivertype);
  225.     announce_lengthy_process("Creating rivers (as connections)");
  226.     for_all_interior_cells(x0, y0) {
  227.     if (probability(t_river_chance(terrain_at(x0, y0)) / 100)) {
  228.         ++numrivers;
  229.         if (numrivers % 5 == 0)
  230.           announce_progress((100 * numrivers) / totalrivers);
  231.         x = x0;  y = y0;
  232.         for (i = 0; i < 20; ++i) {
  233.         /* Find the direction to the lowest adjacent cell. */
  234.         lowdir = -1;
  235.         low = elev_at(x, y);
  236.         for_all_directions(dir) {
  237.             if (point_in_dir(x, y, dir, &x1, &y1)) {
  238.             if (elev_at(x1, y1) <= low) {
  239.                 lowx = x1;  lowy = y1;
  240.                 lowdir = dir;
  241.                 low = elev_at(x1, y1);
  242.             }
  243.             }
  244.         }
  245.         if (lowdir < 0) break;
  246.         if (!(t_liquid(terrain_at(x, y))
  247.               && t_liquid(terrain_at(lowx, lowy)))) {
  248.             set_connection_at(x, y, lowdir, rivertype, TRUE);
  249.         }
  250.         x = lowx;  y = lowy;
  251.         if (!inside_area(x, y)) break;
  252.         }
  253.     }
  254.     }
  255.     finish_lengthy_process();
  256. }
  257.